package com.bungarus.smart.busi;

import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.CacheManagerBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.config.units.MemoryUnit;
import org.ehcache.spi.loaderwriter.CacheLoadingException;
import org.ehcache.spi.loaderwriter.CacheWritingException;

import java.util.*;


public class AccessContainer {
    private static final AccessContainer container = new AccessContainer();
    private static final String ACCESS_ROUTES = "access-routes";
    private static final long CACHE_ENTRIES_COUNT = 1000;
    private static final long CACHE_OFFHEAP_SIZE = 10;

    private final static String IP_SEPARATOR = "::";

    private static CacheManager cacheManager;
    private Cache<String, String> accessRoutesCache;

    private Integer clusterId;

    private AccessContainer() {
        init();
    }

    public static AccessContainer getInstance() {
        return container;
    }

    public static void close() {
        if(null != cacheManager) {
            cacheManager.close();
        }
    }

    private void init() {
        cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
                .withCache(ACCESS_ROUTES,
                        CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, String.class,
                                ResourcePoolsBuilder
                                        .heap(CACHE_ENTRIES_COUNT)
                                        .offheap(CACHE_OFFHEAP_SIZE, MemoryUnit.MB))
                                .build())
                .build(true);
        this.accessRoutesCache = cacheManager.getCache(ACCESS_ROUTES, String.class, String.class);
    }


    /**
     * General method to save object to ehcache
     * @param value
     * @param key
     * @throws Exception
     */
    public void put(String key, String value) throws Exception {
        try {
            this.accessRoutesCache.put(key, value);
        }
        catch (CacheWritingException e) {
            throw new Exception(e);
        }
    }

    /**
     * General method to get object from ehcache
     * @param key
     * @return
     * @throws Exception
     */
    public String get(String key) throws Exception{
        String result;
        try {
            result = this.accessRoutesCache.get(key);
        }
        catch (CacheLoadingException e) {
            throw new Exception(e);
        }
        return result;
    }

    /**
     * Update the ehcache value of access list
     * @throws Exception
     */
    public void saveAccessList(List<String> accessList) throws Exception{
        this.put(getIpListCacheKey(), ipList2String(accessList));
    }

    /**
     * get access list from cache
     * @return
     * @throws Exception
     */
    public List<String> getAccessList() throws Exception{
        return string2IpList(this.get(getIpListCacheKey()));
    }


    /**
     * Get cache key for ip list
     * @return
     */
    private String getIpListCacheKey(){
        return "cluster-" + clusterId;
    }

    /**
     * Convert ip list to string for cache
     * @param ipList
     * @return
     */
    private String ipList2String(List<String> ipList){
        return String.join(IP_SEPARATOR, ipList);
    }

    /**
     * Convert cached string to ip list
     * @param ipListString
     * @return
     */
    private List<String> string2IpList(String ipListString){
        List<String> ipList = new ArrayList<>();
        if(null!=ipListString && !ipListString.isEmpty()){
            ipList = Arrays.asList(ipListString.split(IP_SEPARATOR));
        }
        return ipList;
    }

    public Integer getClusterId() {
        return clusterId;
    }

    public void setClusterId(Integer clusterId) {
        this.clusterId = clusterId;
    }
}

